#ifndef _ANTSYSTEM_H_
#define _ANTSYSTEM_H_

#include "my_io.h"
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <stdexcept>
#include <random>

class AntSystem
{
private:
    int size;
    int cost_min;
    float k;
    float rate_volatilize,const_q,pow_block,pow_keep,pow_put;
    float temperature_lb,temperature_cur,rate_colding;
    vector<float> attraction_block;
    vector<float> attraction_keep;
    vector<float> attraction_put;
public:
    AntSystem(){}
    AntSystem(int n)
    {
        size = n;
        cost_min = INF;
        k = 1.01;

        rate_volatilize = 0.999;
        const_q = 100000;
        pow_block = 2;
        pow_keep = 2;
        pow_put = 2;

        temperature_lb = 1;
        temperature_cur = 900000;
        rate_colding = 0.99;

        // attraction_block = vector<float>(size,10);
        // attraction_keep = vector<float>(size,10);
        // attraction_put = vector<float>(size,10);
        attraction_block = vector<float>(size,temperature_cur);
        attraction_keep = vector<float>(size,temperature_cur);
        attraction_put = vector<float>(size,temperature_cur);
    }

    void refresh()
    {
        cost_min = INF;
        k = 1.01;
        temperature_cur = 900000;
    }

    inline bool random_boolean(float pos)
    {
        float rnd = rand()%100;
        rnd /= 100;
        return rnd < pos;
    }

    inline void volatilizie(int cost)
    {
        for(int i = 0;i < size;++i)
        {
            attraction_block[i] = attraction_block[i]*rate_volatilize;
            attraction_keep[i] = attraction_keep[i]*rate_volatilize;
            attraction_put[i] = attraction_put[i]*rate_volatilize;
        }
    }

    int update_with_state(vector<int> state,int cost)
    {
        if((int)state.size() != size)
        {
            throw runtime_error("n != state.size()\n");
        }
        if(temperature_cur < temperature_lb) return -1;
        if(cost > cost_min)
        {
            float p = exp((float)(cost_min-cost)/temperature_cur*k);
            if(!random_boolean(p))
            {
                k *= 1.01;
                if(k > temperature_cur) return -1;
                PRINTF("t:%f\tk:%f\tcost:%d\n",temperature_cur,k,cost);
                return 0;
            }
        }
        PRINTF("t:%f\tk:%f\tcost:%d\n",temperature_cur,k,cost);
        for(int i = 0;i < size;++i)
        {
            if(state[i] == -1)
            {
                attraction_block[i] += const_q;
            }
            if(state[i] == 0)
            {
                attraction_keep[i] += const_q;
            }
            if(state[i] == 1)
            {
                attraction_put[i] += const_q;
            }
        }
        cost_min = cost;
        k = 1.01;
        volatilizie(cost);
        temperature_cur *= rate_colding;
        return 1;
    }

    vector<int> new_state()
    {
        vector<int> state(size,0);
        for(int i = 0;i < size;++i)
        {
            if(random_put(i))
            {
                state[i] = 1;
            }
        }
        return state;
    }

    bool random_put(int pos)
    {
        if(pos >= size) throw runtime_error("pos >= size in AS");
        float block = pow(attraction_block[pos],pow_block);
        float keep = pow(attraction_keep[pos],pow_keep);
        float put = pow(attraction_put[pos],pow_put);
        float p = put / (block+keep+put);
        return random_boolean(p);
    }
};

#endif